/**
 * 
 */
package com.gr.staffpm.pages.schedule;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.joda.time.DateTime;
import org.wicketstuff.annotation.mount.MountPath;
import org.wicketstuff.annotation.strategy.MountHybrid;

import com.gr.staffpm.StaffPMWebPage;
import com.gr.staffpm.css.CssScope;
import com.gr.staffpm.gof.observer.Subscribable;
import com.gr.staffpm.gof.observer.Subscriber;
import com.gr.staffpm.js.StaffPMJSScope;
import com.gr.staffpm.model.StringModel;
import com.gr.staffpm.pages.schedule.model.Calendar;
import com.gr.staffpm.pages.schedule.model.View;

/**
 * @author Graham Rhodes 14 Mar 2011 16:55:52
 */
@MountHybrid
@MountPath(path = "secure/Schedule")
public class Schedule extends StaffPMWebPage implements IHeaderContributor, Subscriber {

    public static final String NAV_DAY_CLICKED = "nav-day-click";
    public static final String TBAR_PREV_PAGE = "tbar-prev-page";
    public static final String TBAR_NEXT_PAGE = "tbar-next-page";
    public static final String TBAR_MONTH_VIEW = "tbar-month-view";
    public static final String TBAR_WEEK_VIEW = "tbar-week-view";
    public static final String TBAR_DAY_VIEW = "tbar-day-view";
    private final WebMarkupContainer container = new WebMarkupContainer("container");
    private final Label calendarHeader = new Label("calendarHeader", new StringModel(""));
    private final RepeatingView calendars = new RepeatingView("calendars");
    private final List<Calendar> calendarsList = new ArrayList<Calendar>();
    private final ExtCalendarNav datePicker;
    private final ExtCalendarToolbar tbar;
    private final WebMarkupContainer dayContainer = new WebMarkupContainer("dayContainer");
    private final WebMarkupContainer weekContainer = new WebMarkupContainer("weekContainer"), monthContainer = new WebMarkupContainer("monthContainer");
    private final DayView dayView;
    private final WeekView weekView;
    private final MonthView monthView;
    private View view = View.Month;
    private DateTime currentDate = new DateTime();

    public Schedule() {

        datePicker = new ExtCalendarNav("nav");
        tbar = new ExtCalendarToolbar("tbar");
        dayView = new DayView("dayView", this);
        weekView = new WeekView("weekView", this);
        monthView = new MonthView("monthView", this);

        subscribeTo(datePicker);
        subscribeTo(tbar);
        subscribeTo(monthView);
        subscribeTo(weekView);
        subscribeTo(dayView);

        calendarHeader.setDefaultModelObject(monthView.getViewStart().toString("MMMMM dd") + " - " + monthView.getViewEnd().toString("MMMMM dd, yyyy"));
        weekContainer.setVisible(false);
        dayContainer.setVisible(false);

        container.add(calendarHeader);
        container.add(datePicker);
        container.add(tbar);
        monthContainer.add(monthView);
        container.add(monthContainer);
        weekContainer.add(weekView);
        container.add(weekContainer);
        dayContainer.add(dayView);
        container.add(dayContainer);
        container.add(calendars);
        add(container.setOutputMarkupId(true));
    }

    @Override
    public String getTitle() {
        return "My Schedule - StaffPM";
    }

    @Override
    public void renderHead(IHeaderResponse response) {
        response.renderCSSReference(new ResourceReference(CssScope.class, "extjs/ext-all.css"));
        response.renderCSSReference(new ResourceReference(CssScope.class, "extjs/calendar.css"));
        response.renderJavascriptReference(new ResourceReference(StaffPMJSScope.class, "schedule.js"));
    }

    @Override
    public void subscribeTo(Subscribable subscribable) {
        subscribable.addSubscriber(this);
    }

    @Override
    public void notifySubscriber(Object object, AjaxRequestTarget target) {
        if (object instanceof String) {
            DateTime newStartDate = toStartCalDate(new DateTime()), newEndDate = toEndCalDate(newStartDate);
            String note = (String) object;
            if (note.equals(TBAR_NEXT_PAGE)) {
                if (view == View.Month) {
                    newStartDate = toStartOfWeek(monthView.getViewEnd().plusDays(1));
                    newEndDate = toEndCalDate(newStartDate);
                    monthView.updateView(newStartDate);
                    datePicker.updateMonth(newStartDate.plusDays(7));
                    datePicker.submitMonthYearChoice();
                    calendarHeader.setDefaultModelObject(newStartDate.toString("MMMMM dd") + " - " + newEndDate.toString("MMMMM dd, yyyy"));
                } else if (view == View.Week) {
                    newStartDate = weekView.getViewEnd().plusDays(1);
                    newEndDate = newStartDate.plusDays(7);
                    weekView.updateView(newStartDate);
                    datePicker.updateMonth(newStartDate);
                    datePicker.submitMonthYearChoice();
                    calendarHeader.setDefaultModelObject(newStartDate.toString("MMMMM dd") + " - " + newEndDate.toString("MMMMM dd, yyyy"));
                } else if (view == View.Day) {
                    newStartDate = dayView.getViewStart().plusDays(1);
                    dayView.updateView(newStartDate);
                    datePicker.updateMonth(newStartDate);
                    datePicker.submitMonthYearChoice();
                    calendarHeader.setDefaultModelObject(newStartDate.toString("MMMMM dd yyyy"));
                }
            }
            if (note.equals(TBAR_PREV_PAGE)) {
                if (view == View.Month) {
                    newEndDate = toEndOfWeek(monthView.getViewStart().minusDays(1));
                    newStartDate = toStartCalDate(newEndDate);
                    monthView.updateView(newStartDate);
                    datePicker.updateMonth(newStartDate.plusDays(7));
                    datePicker.submitMonthYearChoice();
                    calendarHeader.setDefaultModelObject(newStartDate.toString("MMMMM dd") + " - " + newEndDate.toString("MMMMM dd, yyyy"));
                } else if (view == View.Week) {
                    newEndDate = weekView.getViewStart();
                    newStartDate = newEndDate.minusDays(7);
                    weekView.updateView(newStartDate);
                    datePicker.updateMonth(newStartDate);
                    datePicker.submitMonthYearChoice();
                    calendarHeader.setDefaultModelObject(newStartDate.toString("MMMMM dd") + " - " + newEndDate.toString("MMMMM dd, yyyy"));
                } else if (view == View.Day) {
                    newStartDate = dayView.getViewStart().minusDays(1);
                    dayView.updateView(newStartDate);
                    datePicker.updateMonth(newStartDate);
                    datePicker.submitMonthYearChoice();
                    calendarHeader.setDefaultModelObject(newStartDate.toString("MMMMM dd yyyy"));
                }
            }
            if (note.equals(TBAR_DAY_VIEW)) {
                view = View.Day;
                monthContainer.setVisible(false);
                weekContainer.setVisible(false);
                dayContainer.setVisible(true);
                calendarHeader.setDefaultModelObject(dayView.getViewStart().toString("MMMMM dd yyyy"));
            }
            if (note.equals(TBAR_WEEK_VIEW)) {
                view = View.Week;
                monthContainer.setVisible(false);
                dayContainer.setVisible(false);
                weekContainer.setVisible(true);
                calendarHeader.setDefaultModelObject(weekView.getViewStart().toString("MMMMM dd") + " - " + weekView.getViewEnd().toString("MMMMM dd, yyyy"));
            }
            if (note.equals(TBAR_MONTH_VIEW)) {
                view = View.Month;
                dayContainer.setVisible(false);
                weekContainer.setVisible(false);
                monthContainer.setVisible(true);
                calendarHeader.setDefaultModelObject(monthView.getViewStart().toString("MMMMM dd") + " - " + monthView.getViewEnd().toString("MMMMM dd, yyyy"));
            }
            if (note.equals(NAV_DAY_CLICKED)) {
                newStartDate = monthView.getViewStart().plusDays(7);
                boolean sameMonth = newStartDate.getMonthOfYear() == datePicker.getCurrentDate().getMonthOfYear() && newStartDate.getYear() == datePicker.getCurrentDate().getYear();
                if (view == View.Month && !sameMonth) {
                    newStartDate = datePicker.getCurrentDate().withDayOfMonth(datePicker.getCurrentDate().dayOfMonth().getMinimumValue());
                    newEndDate = datePicker.getCurrentDate().withDayOfMonth(datePicker.getCurrentDate().dayOfMonth().getMaximumValue());
                    if (newStartDate.getDayOfWeek() != 7)
                        newStartDate = newStartDate.minusDays(newStartDate.getDayOfWeek());
                    if (newEndDate.getDayOfMonth() != 6)
                        newEndDate = newEndDate.plusDays(6 - (newEndDate.getDayOfWeek() == 7 ? 0 : newEndDate.getDayOfWeek()));
                    monthView.updateView(newStartDate);
                    calendarHeader.setDefaultModelObject(newStartDate.toString("MMMMM dd") + " - " + newEndDate.toString("MMMMM dd, yyyy"));
                }
            }
        }
        target.addComponent(container);
    }

    private DateTime toEndOfWeek(DateTime date) {
        if (date.getDayOfWeek() == 7)
            return date.minusDays(1);
        if (date.getDayOfWeek() != 6)
            date = date.minusDays(date.getDayOfWeek());
        return date;
    }

    private DateTime toEndCalDate(DateTime startDate) {
        startDate = startDate.plusDays(7).withDayOfMonth(startDate.plusDays(7).dayOfMonth().getMaximumValue());
        if (startDate.getDayOfMonth() != 6) {
            startDate = startDate.plusDays(6 - (startDate.getDayOfWeek() == 7 ? 0 : startDate.getDayOfWeek()));
        }
        return startDate;
    }

    private DateTime toStartOfWeek(DateTime date) {
        if (date.getDayOfWeek() != 7)
            date = date.minusDays(date.getDayOfWeek());
        return date;
    }

    private DateTime toStartCalDate(DateTime endDate) {
        endDate = endDate.withDayOfMonth(endDate.dayOfMonth().getMinimumValue());
        if (endDate.getDayOfWeek() != 7)
            endDate = endDate.minusDays(endDate.getDayOfWeek());
        return endDate;
    }

    public DateTime getCurrentDateTime() {
        return currentDate;
    }

    public void setCurrentDateTime(DateTime dateTime) {
        this.currentDate = dateTime;
    }

    public void addCalendar(final Calendar cal) {
        if (!calendarsList.contains(cal)) {
            calendarsList.add(cal);
            calendars.add(new Label(RandomStringUtils.randomNumeric(10), cal.getName()) {

                private static final long serialVersionUID = 1L;

                @Override
                protected void onComponentTag(ComponentTag tag) {
                    tag.getAttributes().put("class", "ext-cal-evr ext-color-" + cal.getId() + "-ad");
                }

            });
        }
    }

}
